package com.fast.modules.acd.service.impl;

import java.io.IOException;
import java.util.Comparator;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Stream;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.simp.SimpMessagingTemplate;

import com.fast.common.WebSocketConstant;
import com.fast.modules.acd.entity.Node;
import com.fast.modules.acd.entity.Seat;
import com.fast.modules.acd.exception.SkillNotSupportException;
import com.fast.modules.acd.service.AssignService;
import com.fast.modules.acd.service.QueueService;
import com.fast.modules.acd.service.SeatService;
import com.fast.modules.acd.service.SeatStorageService;
import com.fast.modules.websocket.dto.BaseMessage;
import com.fast.modules.websocket.dto.SessionMessage;
import com.fast.modules.websocket.service.UserService;

import lombok.extern.slf4j.Slf4j;

/**
 * 默认的技能分配原则是最长空闲时间原则
 * @author yaoyuquan
 *
 */
@Slf4j
public class AssignServiceImpl implements AssignService, WebSocketConstant {
	

	//每个坐席的最大会话数量
	@Value("${acd.session.max}")
	int maxSession;
	
	@Autowired
	SeatService seatService;
	
	@Autowired
	QueueService queueService;
	
	@Autowired
	SeatStorageService seatStorageService;
	
	@Autowired
	SimpMessagingTemplate template;
	
	@Autowired
	UserService userService;
	
	
	/**
	 * 根据坐席的状态过滤,如果坐席的会话数量达到maxSession，视为繁忙，不会再给这个坐席分配会话
	 */
	Predicate<Seat> filterByStatus = seat -> {
		
		long sessionCount = userService.getSeatSessionSize(seat.getId());
		
		return sessionCount < maxSession;
	};
	
	/**
	 * 根据坐席会话数量排序
	 * 会话数量最少的排前面
	 */
	private Comparator<Seat> sortBySessionCount = Comparator.comparingLong(seat -> {return userService.getSeatSessionSize(seat.getId());});
	
	/**
	 * 根据空闲时间排序
	 * 空闲时间最长的坐席排前面
	 */
	private Comparator<Seat> sortByIdleTime = Comparator.comparingLong(Seat::getIdleTime);


	/**
	 * 分配的详细方法，一般会有定时任务执行这个方法， 也可以手动调用
	 * 会从队列中选取一条数据，并判断数据中的技能当前是否有客服可以支持
	 * 如果没有客服支持这个技能，则抛出SkillNotSupportException
	 * @throws IOException 
	 */
	@Override
	public boolean assign() throws SkillNotSupportException, IOException {

        boolean result = false;
        
		Node node = queueService.pop();
		
		if(node != null) {
			
			if(seatService.support(node.getSkill())) {
				
				Predicate<Seat> filterBySkill = seat -> {
					return seat.getSkills().contains(node.getSkill());
				};
				
				Stream<Seat> stream = seatStorageService.stream();
				
				//根据客服的是否置忙的状态判定
				stream = stream.filter(seat -> {return !seat.isBusy();});
				//根据目前坐席连接的会话数过滤
				stream = stream.filter(filterByStatus);
				//根据坐席技能过滤
				stream = stream.filter(filterBySkill);
				//根据会话数量排序
				stream = stream.sorted(sortBySessionCount);
				//根据空闲时间排序
				stream = stream.sorted(sortByIdleTime);
				
				//判断是否选出分配的坐席
				Optional<Seat> optional = stream.findFirst();
				
				
				if(optional.isPresent()) {
					Seat seat = optional.get();
					result = true;
					seat.assign(node);
					
					//保存客户和坐席的关联数据,建立聊天分组
					userService.addGroup(node.getClientID(), seat.getId());
					//通知客户排队完成
					SessionMessage message = new SessionMessage();
					message.setContent(COMMAND_TALK_BEGIN);
					message.setClientID(node.getClientID());
					message.setSeatID(seat.getId());
					template.convertAndSend(CLIENT_TOPIC_NAME + "/" + node.getClientID(), message);
					//通知坐席,客户会话接入
					BaseMessage seatMessage = new BaseMessage();
					seatMessage.setContent(node);
					template.convertAndSendToUser(seat.getId(), SEAT_TOPIC_NAME, seatMessage);
					//通知队列中的其他用户,修改排队数字
					queueService.notify(0);
				} else {
					//当前没有可用的客服
					queueService.push(node);
				}
			} else {
				log.error("这个技能没有客服支持");
				throw new SkillNotSupportException("这个技能没有客服支持");
			}
		}
		

        
        
		
		return result;
	}
	
	
	
	

}
